package com.itheima.train.common.aspect;

import cn.hutool.log.level.Level;
import com.itheima.train.common.domain.Log;
import com.itheima.train.common.service.LogService;
import com.itheima.train.common.util.RequestHolder;
import com.itheima.train.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Liang
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    private final LogService logService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    public LogAspect(LogService logService) {
        this.logService = logService;
    }

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.itheima.train.common.anno.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        currentTime.set(System.currentTimeMillis());//执行方法前
        Object result = joinPoint.proceed(joinPoint.getArgs());//执行正常的业务逻辑
        //执行方法后
        Log logs = new Log(Level.INFO.name(), System.currentTimeMillis() - currentTime.get());
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        String method = request.getMethod();
        logs.setRequestMode(method);
        logs.setUri(request.getRequestURI());
        if (result != null && result.toString().getBytes().length < 65535) {
            logs.setResult(result.toString());
        }
        currentTime.remove();
        logService.save("", StringUtils.getBrowser(request), StringUtils.getIp(request), method, joinPoint, logs);
        return result;
    }

    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e         exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        try {
            Log logs = new Log(Level.ERROR.name(), System.currentTimeMillis() - currentTime.get());
            currentTime.remove();
            //log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
            if (e.getLocalizedMessage() != null && e.getLocalizedMessage().getBytes().length < 65535) {
                logs.setExceptionDetail(e.getLocalizedMessage());
            }
            HttpServletRequest request = RequestHolder.getHttpServletRequest();
            logs.setRequestMode(request.getMethod());
            logs.setUri(request.getRequestURI());
            logService.save("", StringUtils.getBrowser(request), StringUtils.getIp(request), request.getMethod(), (ProceedingJoinPoint) joinPoint, logs);
        } catch (Exception es) {
            log.error("增加错误日志出错", es);
        }
    }
}
